// Go作者版权所有。版权所有。
// 此源代码的使用受BSD样式的约束
// 可以在许可证文件中找到的许可证。

package load

import (
	"cmd/go/internal/base"
	"cmd/go/internal/str"
	"fmt"
	"strings"
)

var (
	BuildAsmflags   PerPackageFlag // -asmflags
	BuildGcflags    PerPackageFlag // -gcflags
	BuildLdflags    PerPackageFlag // -ldflags
	BuildGccgoflags PerPackageFlag // -gccgoflags
)

// PerPackageFlag是命令行标志实现（flag.Value）
// 这允许为不同的包指定不同的有效标志。
// 有关每个包标志的更多详细信息，请参阅“go help build”。
type PerPackageFlag struct {
	present bool
	values  []ppfValue
}

// ppfValue是单个<pattern>=<flags>每个包的标志值。
type ppfValue struct {
	match func(*Package) bool // 编译模式
	flags []string
}

// 每次在命令行上遇到标志时，都会调用Set。
func (f *PerPackageFlag) Set(v string) error {
	return f.set(v, base.Cwd())
}

// set是set的实现，采用cwd（当前工作目录）以便于测试。
func (f *PerPackageFlag) set(v, cwd string) error {
	f.present = true
	match := func(p *Package) bool { return p.Internal.CmdlinePkg || p.Internal.CmdlineFiles } // 没有模式的默认谓词
	// 为了向后兼容早期的标志拆分，请忽略标志周围的空格。
	v = strings.TrimSpace(v)
	if v == "" {
		// 特殊情况：-gcflags=”“表示命令行参数没有标志
		// （覆盖先前的-gcflags=“-where”）。
		f.values = append(f.values, ppfValue{match, []string{}})
		return nil
	}
	if !strings.HasPrefix(v, "-") {
		i := strings.Index(v, "=")
		if i < 0 {
			return fmt.Errorf("missing =<value> in <pattern>=<value>")
		}
		if i == 0 {
			return fmt.Errorf("missing <pattern> in <pattern>=<value>")
		}
		pattern := strings.TrimSpace(v[:i])
		match = MatchPackage(pattern, cwd)
		v = v[i+1:]
	}
	flags, err := str.SplitQuotedFields(v)
	if err != nil {
		return err
	}
	if flags == nil {
		flags = []string{}
	}
	f.values = append(f.values, ppfValue{match, flags})
	return nil
}

// 字符串是实现flag.Value所必需的。
// 不使用它，因为cmd/go从不调用flag.PrintDefaults。
func (f *PerPackageFlag) String() string { return "<PerPackageFlag>" }

// Present报告该标志是否出现在命令行上。
func (f *PerPackageFlag) Present() bool {
	return f.present
}

// For返回用于给定包的标志。
func (f *PerPackageFlag) For(p *Package) []string {
	flags := []string{}
	for _, v := range f.values {
		if v.match(p) {
			flags = v.flags
		}
	}
	return flags
}
